package com.blue.common.aop;

import com.blue.common.annotation.NotNull;
import com.blue.common.annotation.NotNulls;
import com.blue.common.exception.CustomException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author nanjie.chen
 * Created on 2022/3/20
 */
@Component
@Aspect
public class ParamCheckAop {

    @Pointcut("@annotation(com.blue.common.annotation.NotNull) || @annotation(com.blue.common.annotation.NotNulls)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object checkParam(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        //得到拦截的方法
        Method method = signature.getMethod();
        //获取方法参数注解
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            //存在非空注解判断执行
            if (annotation instanceof NotNulls) {
                Map<String, Object> paramMap = getParamMap(proceedingJoinPoint);
                NotNull[] value = ((NotNulls) annotation).value();
                for (NotNull notNull : value) {
                    paramCheck(paramMap, notNull);
                }
            } else if (annotation instanceof NotNull notNull) {
                Map<String, Object> paramMap = getParamMap(proceedingJoinPoint);
                paramCheck(paramMap, notNull);
            }
        }
        return proceedingJoinPoint.proceed();
    }
    private void paramCheck(Map<String, Object> paramMap, NotNull notNull) throws IllegalAccessException {
        //获取注解中的值
        String paramName = notNull.value();
        String message = notNull.message();
        Set<String> paramNames = paramMap.keySet();
        if (paramNames.contains(paramName)) {
            //String/Integer/Double/Long/Float/Boolean类型参数直接判断
            Object value = paramMap.get(paramName);
            if (value == null) {
                throw new CustomException(message);
            }
        } else {
            //对象类型通过反射获取对象字段值判断
            for (Object value : paramMap.values()) {
                if (value == null) {
                    continue;
                }
                Class<?> aClass = value.getClass();
                Field declaredField;
                try {
                    //获取字段对象
                    declaredField = aClass.getDeclaredField(paramName);
                } catch (NoSuchFieldException ignored) {
                    //如不存在该字段直接跳过
                    continue;
                }
                declaredField.setAccessible(true);
                //获取字段属性做非空判断
                Object obj = declaredField.get(value);
                if (obj == null || "".equals(obj)) {
                    throw new CustomException(message);
                }
            }
        }
    }

    private Map<String, Object> getParamMap(ProceedingJoinPoint proceedingJoinPoint) {
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        String[] paramNames = methodSignature.getParameterNames();
        Object[] values = proceedingJoinPoint.getArgs();
        Map<String, Object> paramMap = new HashMap<>();
        if (paramNames != null && paramNames.length > 0) {
            for (int i = 0; i < paramNames.length; i++) {
                paramMap.put(paramNames[i], values[i]);
            }
        }
        return paramMap;
    }
}
